﻿using Cms.Core.Application.IService.PermissionInfo;
using Cms.Core.Application.IService.RoleInfo;
using Cms.Core.Application.IService.UserInfo;
using Cms.Core.Application.Service.PermissionInfo.Dto;
using Cms.Core.Data.Model;
using Cms.Core.Data.UnitOfWork;
using Cms.Core.Infrastructure.Common;
using Cms.Core.Infrastructure.Dependency;
using Cms.Core.Infrastructure.Extension;
using Cms.Core.Infrastructure.Helps;
using Cms.Core.Infrastructure.Log;
using Cms.Core.Infrastructure.Runtime.Session;
using Cms.Core.Infrastructure.Ui;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Cms.Core.Application.Service.PermissionInfo
{
    /// <summary>
    /// 权限实现类
    /// </summary>
    public class PermissionService : IPermissionService
    {

        private readonly IRepository<SysPermission> _sysPermissionRepository = null;
        private readonly IRepository<SysPermissionModuleMap> _sysPermissionModuleRepository = null;
        private readonly IRepository<SysRolePermissionMap> _sysRolePermissionMapRepository = null;
        private readonly IRepository<SysUserRoleMap> _sysUserRoleMapRepository = null;
        private readonly IRepository<SysRole> _sysRoleRepository = null;
        private readonly IRepository<SysModule> _sysModuleRepository = null;
        private readonly IUserService _userService = null;
        private readonly IUnitOfWork _unitOfWork;
        private readonly IRoleService _roleService = null;

        private readonly ILoggerHelper _loggerHelper = null;
        private readonly ICmsSession _session = null;
        private readonly Guid? _userId = null;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sysPermissionRepository"></param>
        /// <param name="loggerHelper"></param>
        /// <param name="session"></param>
        /// <param name="sysPermissionModuleRepository"></param>
        /// <param name="unitOfWork"></param>
        /// <param name="userService"></param>
        public PermissionService(IRepository<SysPermission> sysPermissionRepository, ILoggerHelper loggerHelper, ICmsSession session, IRepository<SysPermissionModuleMap> sysPermissionModuleRepository, IUnitOfWork unitOfWork, IUserService userService, IRoleService roleService, IRepository<SysRolePermissionMap> sysRolePermissionMapRepository, IRepository<SysRole> sysRoleRepository, IRepository<SysUserRoleMap> sysUserRoleMapRepository, IRepository<SysModule> sysModuleRepository)
        {
            this._sysPermissionRepository = sysPermissionRepository;
            this._loggerHelper = loggerHelper;
            this._session = session;
            this._userId = session.UserId;
            this._sysPermissionModuleRepository = sysPermissionModuleRepository;
            this._unitOfWork = unitOfWork;
            this._userService = userService;
            this._roleService = roleService;
            this._sysRolePermissionMapRepository = sysRolePermissionMapRepository;
            this._sysRoleRepository = sysRoleRepository;
            this._sysUserRoleMapRepository = sysUserRoleMapRepository;
            this._sysModuleRepository = sysModuleRepository;
        }


        /// <summary>
        /// 添加权限
        /// </summary>
        /// <param name="input"></param>
        /// <param name="checkPermissionFunc"></param>
        /// <returns></returns>
        public async Task<OperationResult> AddPermissionAsync(PermissionDto input, Func<string, string, Guid, Task> checkPermissionFunc)
        {
            //var id = input.Id = Guid.NewGuid();
            _unitOfWork.BeginTransaction();
            var result = await _sysPermissionRepository.InsertAsync(input, async o =>
             {

                 await checkPermissionFunc.Invoke(o.Name, o.Code, o.Id);

             }, async (dto, r) =>
             {

                 //r.OrderSort = await MaxOrderSortAsync();
                 r.ModifiedUserId = _userId;
                 r.CreateUserId = _userId;
                 r.OrderSort = await this.MaxOrderSortAsync(input.ParentId, input.OrderSort);
                 return r;
             });

            if (result.Successed)
            {
                if (!input.ModuleId.IsEmptyOrNullOrHasValue())
                {
                    result = await AddSysPermissionModuleMaps(input.ModuleId.Value, input.Id);
                }

            }
            _unitOfWork.Commit();
            return result;
        }

        /// <summary>
        /// 异步添加
        /// </summary>
        /// <param name="moduleId"></param>
        /// <param name="permissionId"></param>
        /// <returns></returns>

        private async Task<OperationResult> AddSysPermissionModuleMaps(Guid moduleId, Guid permissionId)
        {

            return await _sysPermissionModuleRepository.InsertAsync(new SysPermissionModuleMap()
            {
                ModuleId = moduleId,
                PermissionId = permissionId,
                CreateUserId = _userId,
                ModifiedUserId = _userId,
                IsDelete = false
            });
        }

        /// <summary>
        /// 异步更新或者更新权限
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<OperationResult> UpdateOrAddPermissionAsync(PermissionDto input)
        {
            input.Action = input.Action?.Trim();
            Func<string, string, Guid, Task> checkPermissionFunc = async (name, code, id) =>
            {
                CheckPermissionIsNullOrEmpty(name, code);
                await CheckPermissionIsExistAsync(name, code, id);

            };

            if (input.Id == Guid.Empty)
            {
                return await this.AddPermissionAsync(input, checkPermissionFunc);
            }
            return await this.UpdatePermissionAsync(input, checkPermissionFunc);
        }

        /// <summary>
        /// 更新权限异步
        /// </summary>
        /// <param name="input"></param>
        /// <param name="checkPermissionFunc"></param>
        /// <returns></returns>
        public async Task<OperationResult> UpdatePermissionAsync(PermissionDto input, Func<string, string, Guid, Task> checkPermissionFunc)
        {
            _unitOfWork.BeginTransaction();
            var result = await _sysPermissionRepository.UpdateNotQueryAsync(input, async (dto, Permission) =>
            {
                await checkPermissionFunc.Invoke(dto.Name, dto.Code, dto.Id);
            }, async (dto, r) =>
            {

                r.ModifiedUserId = _userId;
                r.OrderSort = await this.MaxOrderSortAsync(input.ParentId, input.OrderSort);
                return r;
            },
              o => o.Name,
              o => o.Code,
              o => o.Icon,
              o => o.Description,
              o => o.ModifiedTime,
              o => o.ModifiedUserId,
              o => o.IsEnabled,
              o => o.Type,
              o => o.ParentId,
              o => o.Level,
              o => o.Action,
              o => o.OrderSort,
              o=>o.IsDisplay);
            if (result.Successed)
            {
                var permissionModule = await _sysPermissionModuleRepository.QueryNotDelete.Where(o => o.PermissionId == input.Id)?.FirstOrDefaultAsync();
                if (permissionModule.IsNotNull())
                {
                    result = await _sysPermissionModuleRepository.SoftDeleteAsync(permissionModule.Id);

                }
                if (result.Successed && !input.ModuleId.IsEmptyOrNullOrHasValue())
                {
                    result = await this.AddSysPermissionModuleMaps(input.ModuleId.Value, input.Id);
                }
            }
            _unitOfWork.Commit();
            return result;
        }

        /// <summary>
        /// 得到权限分页信息
        /// </summary>
        /// <param name="pageRequestData">分页请求数据</param>
        /// <returns></returns>

        public async Task<PageResult> GetPermissionPageDataAsync(PageRequestData pageRequestData)
        {
            pageRequestData.NotNull(nameof(pageRequestData));
            var filter = FilterHelp.ToFilterExpression<SysPermission>(pageRequestData.Filters);
            filter.NotNull(nameof(filter));

            var query = await _sysPermissionRepository.QueryNotDelete.ToPageAsync<SysPermission, dynamic>(filter, pageRequestData, o => new
            {
                Id = o.Id,
                ParentId = o.ParentId,
                Level = o.Level,
                Name = o.Name,
                Code = o.Code,
                OrderSort = o.OrderSort,
                IsEnabled = o.IsEnabled
            });
            return query.ToPageResult();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="pageRequestData"></param>
        /// <returns></returns>
        public async Task<PageResult<PermissionTreeItem>> GetPermissionListAsync(PageRequestData pageRequestData)
        {
            pageRequestData.NotNull(nameof(pageRequestData));
            //var filter = FilterHelp.ToFilterExpression<SysPermission>(pageRequestData.Filters);
            //filter.NotNull(nameof(filter));
            var list = await _sysPermissionRepository.QueryNotDelete.ToDto<SysPermission, PermissionDto>().ToListAsync();

            Func<PermissionDto, ICollection<PermissionDto>, PermissionTreeItem> getPermissionTreeItem = null;
            getPermissionTreeItem = (dto, suoure) =>
              {

                  PermissionTreeItem item = new PermissionTreeItem(dto);
                  var childs = suoure.Where(o => o.ParentId == dto.Id);
                  foreach (var child in childs)
                  {
                      PermissionTreeItem childPermission = getPermissionTreeItem(child, suoure);

                      item.children.Add(childPermission);
                  }
                  return item;
              };

            var roots = list.Where(o => o.ParentId == null).ToList();

            var datas = (from root in roots
                         let suoure = list.Where(o => o.ParentId.IsNotNull()).ToList()
                         select getPermissionTreeItem(root, suoure)
                         );


            return new PageResult<PermissionTreeItem>()
            {
                Data = datas.ToList(),
                Message = "查询成功",
                Success = true
            };
        }

        private async Task<IEnumerable<PermissionDto>> GetPermissionsToDto()
        {
            return (await _sysPermissionRepository.QueryNotDelete.ToDto<SysPermission, PermissionDto>().ToListAsync());
        }

        /// <summary>
        /// 异步得到权限树转成级联选择器
        /// </summary>
        /// <returns></returns>

        public async Task<OperationResult> GetPermissionTreeCascaderItemAsync()
        {


            var list = await _sysPermissionRepository.QueryNotDelete.ToDto<SysPermission, PermissionDto>().ToListAsync();

            Func<PermissionDto, ICollection<PermissionDto>, PermissionTreeCascaderItem> getPermissionTreeItem = null;
            getPermissionTreeItem = (dto, suoure) =>
            {

                PermissionTreeCascaderItem item = new PermissionTreeCascaderItem(dto);
                var childs = suoure.Where(o => o.ParentId == dto.Id);
                foreach (var child in childs)
                {
                    PermissionTreeCascaderItem childPpermission = getPermissionTreeItem(child, suoure);

                    item.Children.Add(childPpermission);

                }
                item.Children = item.Children.Count() > 0 ? item.Children : null;
                return item;
            };

            var roots = list.Where(o => o.ParentId == null).ToList();

            var datas = (from root in roots
                         let suoure = list.Where(o => o.ParentId.IsNotNull()).ToList()
                         select getPermissionTreeItem(root, suoure)
                         );

            return new OperationResult()
            {
                Data = datas.ToList(),
                Message = "查询成功"
            };
        }
        /// <summary>
        /// 最大排序号
        /// </summary>
        /// <returns></returns>
        public async Task<int> MaxOrderSortAsync(Guid? parentId, int orderSort = 0)
        {
            if (orderSort == 0)
            {
                int? maxOrderSort = await _sysPermissionRepository.QueryNotDelete.Where(o => o.ParentId == parentId).MaxAsync(o => (int?)o.OrderSort);
                return (maxOrderSort.HasValue ? maxOrderSort.Value + 1 : 0);
            }
            return orderSort;

        }
        private void CheckPermissionIsNullOrEmpty(string name, string code)
        {
            if (name.IsNullOrWhiteSpace())
            {
                throw new CustomException("权限名不能为空!!");
            }

            //if (code.IsNullOrWhiteSpace())
            //{
            //    throw new CustomException("编码不能为空!!");
            //}



        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="permissionName"></param>
        /// <param name="code">暂时不用</param>
        /// <param name="id"></param>
        /// <returns></returns>
        private async Task<bool> CheckPermissionIsExistAsync(string permissionName, string code, Guid id)
        {

            var isExist = await _sysPermissionRepository.QueryNotDelete.Where(permission => permission.Name == permissionName && (permission.Id != (id != Guid.Empty ? id : Guid.Empty)) && (permission.Type == PermissionType.Menu || permission.Type == PermissionType.List)).AnyAsync();

            if (isExist)
            {
                throw new CustomException("此资源名称已存在！！！");
            }
            return isExist;
        }

        /// <summary>
        /// 异步加载权限表单信息
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>

        public async Task<OperationResult<PermissionDto>> LoadPermissionFormAsync(Guid? id)
        {
            PermissionDto dto = null;
            if (id.IsEmptyOrNullOrHasValue())
            {
                dto = new PermissionDto();
            }
            else
            {

                dto = (await _sysPermissionRepository.GetDtoAsync<PermissionDto>(id.Value));
                string parentName = string.Empty;
                if (dto.ParentId.HasValue)
                {
                    parentName = (await _sysPermissionRepository.GetDtoAsync<PermissionDto>(dto.ParentId.Value))?.Name;
                }
                dto.ParentName = parentName;
                dto.ModuleId = (await _sysPermissionModuleRepository.GetAsync(o => o.IsDelete == false && o.PermissionId == id.Value))?.ModuleId;
            }

            return new OperationResult<PermissionDto>()
            {
                Message = "加载数据成功!!",
                Data = dto,
                Type = OperationResultType.Success,
            };
        }


        /// <summary>
        ///异步软删除 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>

        public async Task<OperationResult> SoftDeletePermissionAsync(Guid id)
        {
            return await _sysPermissionRepository.SoftDeleteAsync(id);
        }

        /// <summary>
        /// 根据角色Id集合得到权限
        /// </summary>
        /// <param name="roleIds"></param>
        /// <returns></returns>
        public IQueryable<SysPermission> GetPermissionsByRoleIds(IEnumerable<Guid> roleIds)
        {
            var permissions = this._sysPermissionRepository.QueryNotDelete.Where(o => o.IsEnabled == true);
            return this._sysRolePermissionMapRepository.QueryNotDelete.Where(o => roleIds.Contains(o.RoleId)).Join(permissions, map => map.PermissionId, p => p.Id, (map, p) => p);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task<IEnumerable<PermissionItemDto>> GetUserAuthorizationUrl(Guid userId)
        {
            //userId.NotNullOrEmpty(nameof(userId));
            var userRoleMaps = this._sysUserRoleMapRepository.QueryNotDelete.Where(o => o.UserId == userId);
            var roles = this._sysRoleRepository.QueryNotDelete.Where(r => r.IsEnabled == true);
            var rolePermissionMaps = this._sysRolePermissionMapRepository.QueryNotDelete;
            var permissionModuleMaps = this._sysPermissionModuleRepository.QueryNotDelete;
            var modules = this._sysModuleRepository.QueryNotDelete.Where(m => m.IsEnabled == true);

            return await userRoleMaps.Join(roles, urm => urm.RoleId, r => r.Id, (urm, r) => new { RoleId = r.Id, RoleName = r.Name })
                         .Join(rolePermissionMaps, r => r.RoleId, rpm => rpm.RoleId, (r, rpm) => new { r.RoleName, rpm.PermissionId })
                         .Join(permissionModuleMaps, rpm => rpm.PermissionId, pmm => pmm.PermissionId, (rpm, pmm) => new { rpm.RoleName, pmm.ModuleId })
                         .Join(modules, pmm => pmm.ModuleId, m => m.Id, (pmm, m) => new { pmm.RoleName, m.LinkUrl })
                         .Select(o => new PermissionItemDto
                         {
                             RoleName = o.RoleName,
                             Url = o.LinkUrl
                         }).ToListAsync();
        }

        /// <summary>
        /// 根据菜单编码得到当前用户所有已授权的按钮
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public async Task<IEnumerable<dynamic>> GetCurrentUserAuthorizationAllButtonByParentNameAsync(string name)
        {
            _userId.NotNull(nameof(_userId));
            name.NotNullOrEmpty(nameof(name));
            var permission = this._sysPermissionRepository.QueryNotDelete;
            var pp = permission.Where(p => p.Name == name).Select(p => p.Id).Take(1);
            var buttonsList = await _sysRoleRepository.QueryNotDelete
            .Join(this._sysUserRoleMapRepository.QueryNotDelete
            .Where(u => u.UserId == _userId.AsTo<Guid>()), r => r.Id, urMap => urMap.RoleId, (r, urMap) => new { RoleId = r.Id })
            .Join(this._sysRolePermissionMapRepository.QueryNotDelete, urMap => urMap.RoleId, rpMap => rpMap.RoleId, (urMap, rpMap) => new { rpMap.PermissionId })
            .Join(this._sysPermissionRepository.QueryNotDelete, rpMap => rpMap.PermissionId, p => p.Id, (rpMap, p) => p)
            .OrderBy(p => p.OrderSort)
            .Where(p => pp.Contains(p.ParentId.Value) && p.Type == PermissionType.Button)
            .Select(p => new
            {
                p.Id,
                p.Name,
                p.Action,
                p.Icon

            }).ToListAsync();
            return buttonsList;


        }

        /// <summary>
        /// 得到菜单
        /// </summary>
        /// <returns></returns>
        public async Task<OperationResult<List<MenuDto>>> GetAllMenusAsync()
        {
            _userId.NotNull(nameof(_userId));
            var userRoleMaps = this._sysUserRoleMapRepository.QueryNotDelete.Where(o => o.UserId == _userId.AsTo<Guid>());
            var roles = this._sysRoleRepository.QueryNotDelete.Where(r => r.IsEnabled == true);
            var rolePermissionMaps = this._sysRolePermissionMapRepository.QueryNotDelete;
            var permissionModuleMaps = this._sysPermissionModuleRepository.QueryNotDelete;
            var modules = this._sysModuleRepository.QueryNotDelete.Where(m => m.IsEnabled == true);
            var permissions = this._sysPermissionRepository.QueryNotDelete.Where(p => p.Type == PermissionType.Menu&&p.IsDisplay==true);
            var list = await userRoleMaps.Join(roles, urMap => urMap.RoleId, r => r.Id, (urMap, r) => new { urMap.RoleId })
                .Join(rolePermissionMaps, r => r.RoleId, rpMap => rpMap.RoleId, (r, rpMap) => new { rpMap.PermissionId })
                .Join(permissions, rpMap => rpMap.PermissionId, p => p.Id, (rpMap, p) => new { p.Id, p.Name, p.OrderSort, p.ParentId ,p.Icon})
                .Join(permissionModuleMaps, p => p.Id, pmMap => pmMap.PermissionId, (p, pmMap) => new { Id = pmMap.PermissionId, p.Name, p.ParentId, p.OrderSort, pmMap.ModuleId,p.Icon })
                .Join(modules, pmMap => pmMap.ModuleId, m => m.Id, (pmMap, m) => new { pmMap.ParentId, pmMap.Id, pmMap.Name, pmMap.OrderSort, Paht = m.LinkUrl,pmMap.Icon }).ToListAsync();
            var datas = list.GroupBy(o => o.Id).Select(o =>
            new PermissionModuleDto {
                Id = o.Key,
                Name = o.FirstOrDefault()?.Name,
                OrderSort = o.FirstOrDefault()?.OrderSort ?? 0,
                ParentId = o.FirstOrDefault()?.ParentId,
                Path = o.FirstOrDefault()?.Paht,
                Icon = o.FirstOrDefault()?.Icon,
    
            }).OrderBy(o=>o.OrderSort);

            Func<PermissionModuleDto, ICollection<PermissionModuleDto>, MenuDto> getMenuList = null;
            getMenuList = (dto, suoure) =>
            {

                MenuDto item = new MenuDto(dto);
                var childs = suoure.Where(o => o.ParentId == dto.Id);
                foreach (var child in childs)
                {
                    MenuDto childmenu = getMenuList(child, suoure);

                    item.Children.Add(childmenu);

                }
                //item.Children = item.Children.Count() > 0 ? item.Children : null;
                return item;
            };

            var roots = datas.Where(o => o.ParentId == null).ToList();

            var menuList = (from root in roots
                         let suoure = datas.Where(o => o.ParentId.IsNotNull()).ToList()
                         select getMenuList(root, suoure)
                         );
            return new OperationResult<List<MenuDto>>()
            {
                Message = "加载数据成功!!",
                Data = menuList.ToList(),
                Type = OperationResultType.Success,
            };

        }

    }





    /// <summary>
    /// 
    /// </summary>
    public class PermissionTreeItem
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="dto"></param>
        public PermissionTreeItem(PermissionDto dto)
        {
            this.Id = dto.Id;
            this.ParentId = dto.ParentId;
            this.Level = dto.Level;
            this.Name = dto.Name;
            this.Code = dto.Code;
            this.OrderSort = dto.OrderSort;
            this.IsEnabled = dto.IsEnabled;
            this.Type = dto.Type;
            this.CreateTime = dto.CreateTime;
            this.ModifiedTime = dto.ModifiedTime;
            this.IsDisplay = dto.IsDisplay;
            this.Action = dto.Action;

            this.children = new List<PermissionTreeItem>();
            this.Icon = dto.Icon;
        }
        /// <summary>
        /// 
        /// </summary>
        public Guid Id { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public Guid? ParentId { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public int Level { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string Code { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public int OrderSort { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public bool IsEnabled { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public PermissionType Type { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public virtual DateTime CreateTime { get; set; }


        /// <summary>
        /// 方法名,方法标识
        /// </summary>
        public string Action { get; set; }


        /// <summary>
        /// 修改时间
        /// </summary>
        public virtual DateTime? ModifiedTime { get; set; }
        /// <summary>
        /// 是否显示 
        /// </summary>
        public bool IsDisplay { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public ICollection<PermissionTreeItem> children { get; set; }

        /// <summary>
        /// 图标
        /// </summary>
        public string Icon { get; set; }
    }

    /// <summary>
    /// Cascader破控件专用
    /// </summary>
    public class PermissionTreeCascaderItem
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="dto"></param>
        public PermissionTreeCascaderItem(PermissionDto dto)
        {
            this.Value = dto.Id.ToString();

            this.Label = dto.Name;
            this.Children = new List<PermissionTreeCascaderItem>();


        }

        /// <summary>
        /// 值
        /// </summary>
        [JsonProperty("value")]
        public string Value { get; set; }

        /// <summary>
        /// 显示
        /// </summary>
        [JsonProperty("label")]
        public string Label { get; set; }

        /// <summary>
        /// 子节点
        /// </summary>
        [JsonProperty("children")]
        public ICollection<PermissionTreeCascaderItem> Children { get; set; }





    }


}
